import * as d3 from "d3"
import moment from "moment"
import { computeMothMap, computeDayTicks, computeMonthTicks } from "./helper"


export const _xAxisClipPath = "x-axis-clipPath", _yAxisClipPath = "y_axis_clip_path"

export function createXAxis(svg, ctx) {
    const { width, height, marginTop, marginRight, marginBottom, marginLeft, startTime, endTime } = ctx

    let xConfig = {
        x1: marginLeft,
        x2: width - marginRight,
        y: marginTop,
    }
    ctx.xConfig = xConfig

    const { x1, x2, y } = xConfig

    const xScale = d3.scaleTime()
        .domain([startTime, endTime])
        .range([x1, x2]);


    const xAxis = (g, x) => {
        if (x) {
            ctx._xScale = x
        }
        g.call(d3.axisTop(x).ticks(width / 80).tickSizeOuter(0))
    }

    const gx = svg.append("g")
        .attr("transform", `translate(0,${y * 1.5})`)
        .attr("visibility", "hidden")
        .call(xAxis, xScale);

    const zoom = d3.zoom()
        .scaleExtent([5, 35])
        .extent([[x1, 0], [x2, 0]])
        .translateExtent([[x1, -0], [x2, 0]])
        .on("zoom", zoomed);
    svg.call(zoom)

    ctx._updateXDomains = (start, end) => {
        xScale.domain([moment(start), moment(end)])
        gx.call(xAxis, xScale)

        createMonth(xScale)

        let svgWidth = ctx.width
        let monthWidth = 3 * 40
        let count = Math.floor(svgWidth / monthWidth)
        const months = moment(end).diff(moment(start), 'months');
        const minSScale = Math.ceil(months / count)
        const maxScale = minSScale * 5
        zoom.scaleExtent([minSScale, maxScale])

        let oldTransform = d3.zoomTransform(svg.node())
        const new_transform = d3.zoomIdentity.translate(oldTransform.x, 0).scale(oldTransform.k);
        svg.call(zoom.transform, new_transform);
        // svg.transition().duration(350)
        //     .call(zoom.scaleTo, minSScale, [xScale(moment(start)), 0]);

    }

    ctx._updateXDomains(ctx.startTime, ctx.endTime)


    function zoomed(event) {
        const xz = event.transform.rescaleX(xScale);
        // console.log("xz", xz.domain(), xz.range())
        gx.call(xAxis, xz);

        createMonth(xz)

        ctx.zoomChanged()
    }

    function createMonth(scale) {
        let domain = scale.domain()
        let mm = computeMothMap(domain[0], domain[1])
        let ticks = computeMonthTicks(mm)
        let months = ticks.map(t => moment(t).startOf('month'))

        if (ctx.xRowLine) {
            ctx.xRowLine.remove()
        }
        ctx.xRowLine = createXRowLine(svg, { ...ctx, className: "xRowLine" })

        months.forEach(m => {
            let nextMonth = moment(m).add(1, 'month').startOf('month')
            let step = scale(nextMonth) - scale(m)
            let x = scale(m)
            appendXRowTick({ line: ctx.xRowLine, x, text: m, step, scale }, ctx)

        })

        createRowSplitLines(svg, ctx.xRowLine, ctx)
    }

    // svg.call(zoom)
    // Initial zoom.
    // svg.call(zoom)
    //     .transition()
    //     .duration(750)
    //     .call(zoom.scaleTo, 5, [xScale(moment(startTime)), 0]);


    return { xScale, xAxis, gx }
}

export function createYAxis(svg, ctx) {
    const { width, height, marginTop, marginRight, marginBottom, marginLeft, yUpdate } = ctx
    let maxLevel = ctx.yMaxLevel, _currentK = 1, _preTansformY

    const yConfig = {
        clipId: _yAxisClipPath,
        visibility: "hidden",
        y1: marginTop,
        y2: height - marginBottom,
        translateY: 0,
        bottom: height - marginBottom,
        step: 60,
        clipRect: {
            x: -40,
            y: marginTop,
            width: width - marginLeft - marginRight + 40,
            height: height - marginTop - marginBottom
        },
        zoomRect: {
            x: width - 40,
            y: marginTop,
            width: 40,
            height: height - marginBottom - marginTop
        }
    }

    const yScale = d3.scaleBand([], [yConfig.y1, yConfig.y2]).padding(0).align(0);
    ctx._yScale = yScale

    const yAxis = d3.axisLeft(yScale).tickSizeOuter(0)

    createClipPath(svg, yConfig.clipId, yConfig.clipRect)

    const gy = svg.append("g")
        .attr("clip-path", `url(#${yConfig.clipId})`)
        .attr("class", "y-axis")
        .attr("visibility", yConfig.visibility)
        .attr("transform", `translate(60,${yConfig.translateY})`)
        .call(yAxis, yScale);


    const yZoomRect = svg.append("rect")
        .attr("x", yConfig.zoomRect.x)
        .attr("y", yConfig.zoomRect.y)
        .attr("width", yConfig.zoomRect.width)
        .attr("height", yConfig.zoomRect.height)
        .attr("fill", 'rgba(135,206,235,0.4)')
        .attr("visibility", yConfig.visibility)

    const zoom = d3.zoom()
        .scaleExtent([1, 1])
        .on("zoom", zoomed)

    yZoomRect.call(zoom)

    ctx.yZoomInited(zoom)
    ctx._updateYDomains = (datas) => {
        // console.log("datas", datas)
        let totalStep = datas.length * yConfig.step
        let y2 = totalStep + yConfig.y1
        yConfig.canTranslateY = y2 > yConfig.bottom
        yConfig.totalStep = totalStep
        yConfig.minY1 = yConfig.bottom - totalStep
        yConfig.y2 = y2
        let y1 = yConfig.y1

        yScale.domain(datas).range([y1, y2])
        gy.call(yAxis)

        let extent = [[0, y1], [0, Math.min(height - marginBottom, y2)]]
        let transExtent = [[0, y1], [0, Math.max(height - marginBottom, y2)]]
        zoom.extent(extent)
        zoom.translateExtent(transExtent)

        updateYColTicks(svg, ctx, yScale)
        ctx.updateProjects(yScale)

        // yZoomRect.transition().duration(750).call(zoom.translateTo, 0, -60, [0, yScale(datas[2])]);

        // let zoomSelection = gy

        // let oldTransform = d3.zoomTransform(zoom)
        // console.log("oldTransform", oldTransform)

        // const transform = d3.zoomIdentity.translate(0, _preTansformY || 0).scale(1.0);
        // let targetId = datas[3]
        // let ty = -(yScale(targetId) - height + marginBottom)
        // const transform = d3.zoomIdentity.translate(0, 0).scale(1.0);
        // zoomSelection.call(zoom.transform, new_transform);

        // // console.log("*_preTansformY", _preTansformY)

        // // zoom.translateTo(zoomSelection, 0, 91)

        // let oldTransform = d3.zoomTransform(zoom)
        // console.log("oldTransform", oldTransform)

        // setTimeout(() => {
        //     _preTansformY = 0
        //     // zoomed({ transform })
        //     console.log("transform", transform)
        //     // zoomSelection.call(zoom.transform, transform);
        //     zoom.scaleTo(svg, 1.0, [0, yScale(targetId)])
        // }, 1000)

    }

    function transformChanged(transformY) { }


    function zoomed(event) {
        if (!yConfig.canTranslateY) return

        let transformY = event.transform.y
        if (transformY === 0) return

        if (!_preTansformY) {
            _preTansformY = 0
        }

        if (Math.abs(transformY - _preTansformY) < 0.001) {
            return
        }

        let direction = _preTansformY > transformY ? "up" : "down"

        _preTansformY = transformY

        let range = yScale.range()
        if (direction === "up") {
            range[0] = event.transform.applyY(range[0])
            range[0] = Math.max(range[0], yConfig.minY1)
        } else {
            range[0] = event.transform.invertY(range[0])
            range[0] = Math.min(range[0], yConfig.y1)
        }
        range[1] = range[0] + yConfig.totalStep
        // console.log("range", range)
        yScale.range(range)
        gy.call(yAxis);
        ctx.yZoomUpdated(yScale)
        updateYColTicks(svg, ctx, yScale)
        ctx.zoomChanged()
    }

}


export function createRowSplitLines(svg, selection, ctx) {
    let allRowTicks = selection.selectAll(".split-line")
    // console.log("*allRowTicks", allRowTicks)
    let arr = []
    allRowTicks.each(function (d) {
        let line = d3.select(this).attr("y1", ctx.height)
    })
}


export function createClipPath(svg, clipId, { x, y, width, height }) {
    let selection = svg.select(`#${clipId}`)
    if (selection.empty()) {
        let defs = svg.select("defs")
        selection = defs.append("clipPath")
            .attr("id", clipId)
            .append("rect")
            .attr("x", x)
            .attr("y", y)
            .attr("width", width)
            .attr("height", height);

    }

    return selection

}

export function createYColLine(svg, ctx, scale) {
    const { marginTop, height, marginBottom } = ctx
    const offsetX = 30
    let lineG = svg.append("g").attr("class", "yColLine").attr('transform', `translate(0,0)`)
        .attr("clip-path", `url(#${_yAxisClipPath})`)
    createYColTicks(lineG, scale, ctx)

    return lineG
}

export function createYColTicks(g, scale, ctx) {

    let strokeColor = "rgba(0,0,0,0.3)"
    // strokeColor = "red"
    let domain = scale.domain()
    let step = scale.step()
    domain.forEach((k) => {
        let ty = scale(k)
        let line = g.append("line").attr("x2", ctx.width).attr("stroke-width", 0.5).attr("stroke", strokeColor).attr("transform", `translate(0,${ty})`)

    })

}
export function updateYColTicks(svg, ctx, scale) {
    if (ctx.yLine) {
        ctx.yLine.remove()
    }
    ctx.yLine = createYColLine(svg, ctx, scale)
}

export function createXRowLine(svg, ctx) {
    const { marginLeft, width, marginRight, xConfig: { x1, x2, y }, className = "month-line", height, marginBottom } = ctx

    let clipId = _xAxisClipPath
    createClipPath(svg, clipId, { x: x1, y: -y, width: x2 - x1, height: height - marginBottom })

    let lineG = svg.append("g").attr("class", "XRowLine").attr('transform', `translate(0,${y})`)
        .attr("clip-path", `url(#${clipId})`)

    lineG.append("rect")
        .attr("x", x1)
        .attr("y", -y)
        .attr("width", x2 - x1)
        .attr("height", y)
        .attr("fill", "none")

    lineG.append("line")
        .attr("class", className)
        .attr("stroke", "black")
        .attr('stroke-width', 2)
        .attr('x1', x1)
        .attr('x2', x2)

    return lineG

}


export function appendXRowTick({ line, x, text, step, scale }, { marginTop }) {
    let fontSize = 14
    let monthText = moment(text).format("YYYY-MM")
    let showMonth = fontSize * monthText.length * 0.9 <= step

    let tick = line.append('g').attr("class", "tick x-row-tick").attr("opacity", 1).attr("transform", `translate(${x},0)`)
    tick.append("line").attr("y2", -marginTop).attr("stroke", "currentColor")
    tick.append("line").attr("class", "split-line").attr("y2", 0).attr("stroke-width", 1).attr("stroke", "rgba(0,0,255,0.4)")
    tick.append("text").attr("x", step * 0.5).attr("y", -29)
        .attr("text-anchor", "middle")
        .attr("visibility", showMonth ? "visible" : "hidden")
        .attr('font-size', `${fontSize}px`)
        .text(() => {
            return monthText

        })

    let dayCount = moment(text).daysInMonth();
    let dayWidth = 20
    let planCount = Math.round(step / dayWidth)
    let stepDay = Math.ceil(dayCount / planCount)
    let startDay = moment(text).startOf("month")
    let endDay = moment(text).endOf("month")

    planCount = Math.ceil(dayCount / stepDay)

    let days = []
    Array(planCount).fill(0).map((t, index) => {
        if (index > 0) {
            let d = moment(startDay).add(index * stepDay, "days")
            if (d.isBefore(endDay)) {
                days.push(d)
            }

        }

    })

    days.forEach(d => {
        let dayX = scale(d)
        let tick = line.append('g').attr("class", "tick x-row-tick").attr("opacity", 1).attr("transform", `translate(${dayX},0)`)
        tick.append("line").attr("y2", -6).attr("stroke", "currentColor")
        tick.append("line").attr("class", "split-line").attr("y2", 0).attr("stroke-width", 0.3).attr("stroke", "rgba(0,0,0,0.3)")
        tick.append("text").attr("y", -9)
            .attr("text-anchor", "middle")
            .attr("visibility", "visible")
            .attr("font-size", "12px")
            .text(() => {
                return moment(d).format("DD")

            })
    })

    // let ddDescs_ = days.map(t => moment(t).format("YYYY-MM-DD"))
    // console.log("ddDescs_", ddDescs_, planCount, dayCount, stepDay, moment(text).format("YYYY-MM"), startDay.format("YYYY-MM-DD"), endDay.format("YYYY-MM-DD"))

}

